<?php
/** 
 * EGP Framework
 *
 * LICENSE
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author     Akon(番茄红了) <aultoale@gmail.com>
 * @copyright  Copyright (c) 2008 (http://www.tblog.com.cn)
 * @license    http://www.gnu.org/licenses/gpl.html     GPL 3
 */

!defined('EGP_LIB_DIR') && die('Access Deny!');

/**
 * HTTP 响应处理
 *
 * @package    classes
 * @author     Akon(番茄红了) <aultoale@gmail.com>
 * @copyright  Copyright (c) 2008 (http://www.tblog.com.cn)
 * @license    http://www.gnu.org/licenses/gpl.html     GPL 3
 */
class EGP_Http_Request
{

    /**
     * 存储单件模式实例
     *
     * @var EGP_Http_Request
     */
    private static $_instance = null;

    /**
     * REQUEST_URI
     *
     * @var string
     */
    private $_requestUri = null;

    /**
     * BASE_URL
     *
     * @var string
     */
    private $_baseUrl = null;

    /**
     * BASE_PATH
     *
     * @var string
     */
    private $_basePath = null;

    /**
     * PATH_INFO
     *
     * @var string
     */
    private $_pathInfo = null;

    /**
     * QUERY_PATH
     *
     * @var string
     */
    private $_queryPath = null;

    /**
     * 内部参数存储
     *
     * @var array
     */
    private $_params = array();

    /**
     * 单件模式调用方法
     *
     * @return EGP_Http_Request
     */
    public static function getInstance()
    {
        if (!self::$_instance instanceof self)
            self::$_instance = new self();
        return self::$_instance;
    }

    /**
     * 构造方法
     *
     */
    protected function __construct()
    {}

    /**
     * 获取主机名
     *
     * @return string
     */
    public function getHttpHost()
    {
        $httpHost = isset($_SERVER['HTTP_X_FORWARDED_HOST']) ?
                    $_SERVER['HTTP_X_FORWARDED_HOST'] :
                    (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '');
        return strtolower($httpHost);
    }

    /**
     * 获取 REQUEST_URI
     *
     * @return string
     */
    public function getRequestUri()
    {
        if (null == $this->_requestUri) {
            $requestUri = '';
            if (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
                $requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
            } elseif (isset($_SERVER['REQUEST_URI'])) {
                $requestUri = $_SERVER['REQUEST_URI'];
            } elseif (isset($_SERVER['ORIG_PATH_INFO'])) {
                $requestUri = $_SERVER['ORIG_PATH_INFO'];
                !empty($_SERVER['QUERY_STRING']) && $requestUri .= '?' . $_SERVER['QUERY_STRING'];
            }
            $this->_requestUri = $requestUri;
        }
        return $this->_requestUri;
    }

    /**
     * 获取 BASE_URL
     *
     * @return string
     */
    public function getBaseUrl()
    {
        if (null === $this->_baseUrl) {
            $filename = basename($_SERVER['SCRIPT_FILENAME']);
            if (basename($_SERVER['SCRIPT_NAME']) === $filename) {
                $baseUrl = $_SERVER['SCRIPT_NAME'];
            } elseif (basename($_SERVER['PHP_SELF']) === $filename) {
                $baseUrl = $_SERVER['PHP_SELF'];
            } elseif (isset($_SERVER['ORIG_SCRIPT_NAME']) &&
                      basename($_SERVER['ORIG_SCRIPT_NAME']) === $filename) {
                $baseUrl = $_SERVER['ORIG_SCRIPT_NAME'];
            } else {
                $path    = $_SERVER['PHP_SELF'];
                $segs    = explode('/', trim($_SERVER['SCRIPT_FILENAME'], '/'));
                $segs    = array_reverse($segs);
                $index   = 0;
                $last    = count($segs);
                $baseUrl = '';
                do {
                    $seg     = $segs[$index];
                    $baseUrl = '/' . $seg . $baseUrl;
                    ++$index;
                } while (($last > $index) &&
                        (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos));
            }
            $requestUri = $this->getRequestUri();

            if (0 === strpos($requestUri, $baseUrl))
                $baseUrl = $baseUrl;
            elseif (0 === strpos($requestUri, dirname($baseUrl)))
                $baseUrl = rtrim(dirname($baseUrl), '/');
            elseif (!strpos($requestUri, basename($baseUrl)))
                $baseUrl = '';
            elseif ((strlen($requestUri) >= strlen($baseUrl)) &&
                   ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0)))
                $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl));
            $this->_baseUrl = $baseUrl;
        }
        return $this->_baseUrl;
    }

    /**
     * 获取 BASE_PATH
     *
     * @return string
     */
    public function getBasePath()
    {
        if (null === $this->_basePath) {
            $filename = basename($_SERVER['SCRIPT_FILENAME']);
            $basePath = $baseUrl = $this->getBaseUrl();
            basename($baseUrl) === $filename && $basePath = dirname($baseUrl);
            $this->_basePath = rtrim(str_replace('\\', '/', $basePath), '/');
        }
        return $this->_basePath;
    }

    /**
     * 获取 PATH_INFO
     *
     * @return string
     */
    public function getPathInfo()
    {
        if (null == $this->_pathInfo) {
            $baseUrl = $this->getBaseUrl();
            $requestUri = $this->getRequestUri();
            $pathInfo = '';
            if (!empty($requestUri)) {
                if ($pos = strpos($requestUri, '?'))
                    $requestUri = substr($requestUri, 0, $pos);
                if (empty($baseUrl)) {
                    $pathInfo = $requestUri;
                } else {
                    $pathInfo = substr($requestUri, strlen($baseUrl));
                    $pathInfo === false && $pathInfo = '';
                }
            }
            $this->_pathInfo = $pathInfo;
        }
        return $this->_pathInfo;
    }

    /**
     * 设置查询路径(不包括 /module/controller/action 的其他部分)
     *
     * @param unknown_type $path
     * @return unknown
     */
    public function setQueryPath($path)
    {
        if (!empty($path) && $path != '/') {
            preg_match_all('/[^\/]+(\/[^\/]+)?/', $path, $matches);
            if (isset($matches[0])) {
                foreach ($matches[0] as $match) {
                    @list($key, $value) = explode('/', $match);
                    $_REQUEST[$key] = $_GET[$key] = $value;
                }
            }
        }
        $this->_queryPath = $path;
        return $this;
    }

    /**
     * 获取查询路径
     *
     * @return string
     */
    public function getQueryPath()
    {
        if (null == $this->_queryPath)
            $this->_queryPath = $this->getPathInfo();
        return $this->_queryPath;
    }


    /**
     * 设置 EGP_Http_Request 参数
     *
     * @param  string  $key
     * @param  mixed   $value
     * @return EGP_Http_Request
     */
    public function setParam($key, $value = null)
    {
        if (null == $value && isset($this->_params[$key]))
            unset($this->_params[$key]);
        else
            $this->_params[$key] = $value;
        return $this;
    }

    /**
     * 获取 EGP_Http_Request 参数
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function getParam($key, $default = null)
    {
        if (isset($this->_params[$key]))
            return $this->_params[$key];
        elseif (isset($_REQUEST[$key]))
            return $_REQUEST[$key];
        else
            return $default;
    }

    /**
     * 设置 EGP_Http_Request 参数
     *
     * @param  array  $params
     * @return EGP_Http_Request
     */
    public function setParams(array $params)
    {
        foreach ($params as $key => $value)
            $this->setParam($key, $value);
        return $this;
    }

    /**
     * 获取 EGP_Http_Request 参数
     *
     * @return array
     */
    public function getParams()
    {
        return array_merge($_GET, $_POST, $this->_params);
    }

    /**
     * 获取 Query String 数据
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function getQuery($key = null, $default = null) {
        if (null == $key)
            return $_GET;
        return isset($_GET[$key]) ? $_GET[$key] : $default;
    }

    /**
     * 获取 Http Post 数据
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function getPost($key = null, $default = null) {
        if (null == $key)
            return $_POST;
        return isset($_POST[$key]) ? $_POST[$key] : $default;
    }

    /**
     * 获取 Http Request 数据
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function getRequest($key = null, $default = null) {
        if (null == $key)
            return $_REQUEST;
        return isset($_REQUEST[$key]) ? $_REQUEST[$key] : $default;
    }

    /**
     * 获取 Files Upload 数据
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function getFiles($key = null, $default = null) {
        if (null == $key)
            return $_FILES;
        return isset($_FILES[$key]) ? $_FILES[$key] : $default;
    }

    /**
     * 获取 Http Server 数据
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function getServer($key = null, $default = null) {
        if (null == $key)
            return $_SERVER;
        return isset($_SERVER[$key]) ? $_SERVER[$key] : $default;
    }

    /**
     * 获取 Envionment 数据
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function getEnv($key = null, $default = null) {
        if (null == $key)
            return $_ENV;
        return isset($_ENV[$key]) ? $_ENV[$key] : $default;
    }

    /**
     * 获取 Session 数据
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function getSession($key = null, $default = null) {
        if (null == $key)
            return $_SESSION;
        return isset($_SESSION[$key]) ? $_SESSION[$key] : $default;
    }

    /**
     * 获取 Cookie 数据
     *
     * @param  string  $key
     * @param  mixed   $default
     * @return mixed
     */
    public function getCookie($key = null, $default = null) {
        if (null == $key)
            return $_COOKIE;
        return isset($_COOKIE[$key]) ? $_COOKIE[$key] : $default;
    }

    /**
     * 获取 Http Request 使用的传递方法
     *
     * @return string
     */
    public function getMethod()
    {
        return $this->getServer('REQUEST_METHOD');
    }

    /**
     * 判断是否 Post 方式
     *
     * @return boolean
     */
    public function isPost()
    {
        return 'POST' == $this->getMethod();
    }

    /**
     * Return the value of the given HTTP header. Pass the header name as the
     * plain, HTTP-specified header name. Ex.: Ask for 'Accept' to get the
     * Accept header, 'Accept-Encoding' to get the Accept-Encoding header.
     *
     * @param  string HTTP   header name
     * @return string|false  HTTP header value, or false if not found
     * @throws EGP_Exception
     */
    public function getHeader($header)
    {
        if (empty($header)) {
            throw new EGP_Exception('An HTTP header name is required');
        }

        // Try to get it from the $_SERVER array first
        $temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
        if (!empty($_SERVER[$temp])) {
            return $_SERVER[$temp];
        }

        // This seems to be the only way to get the Authorization header on
        // Apache
        if (function_exists('apache_request_headers')) {
            $headers = apache_request_headers();
            if (!empty($headers[$header])) {
                return $headers[$header];
            }
        }

        return false;
    }

    /**
     * Is the request a Javascript XMLHttpRequest?
     *
     * Should work with Prototype/Script.aculo.us, possibly others.
     *
     * @return boolean
     */
    public function isXmlHttpRequest()
    {
        return ($this->getHeader('X_REQUESTED_WITH') == 'XMLHttpRequest');
    }

    /**
     * 获取 Http Request 数据
     *
     * @param  string  $key
     * @return mixed
     */
    public function get($key)
    {
        switch (strtolower($key)) {
            case 'http_host':   return $this->getHttpHost();
            case 'request_uri': return $this->getRequestUri();
            case 'base_url':    return $this->getBaseUrl();
            case 'base_path':   return $this->getBasePath();
            case 'path_info':   return $this->getPathInfo();
            case 'query_path':  return $this->setQueryPath();
        }
        if (isset($this->_params[$key])) {
            return $this->_params[$key];
        } elseif (isset($_REQUEST[$key])) {
            return $_REQUEST[$key];
        } elseif (isset($_COOKIE[$key])) {
            return $_COOKIE[$key];
        } elseif (isset($_SESSION[$key])) {
            return $_SESSION[$key];
        } elseif (isset($_SERVER[$key])) {
            return $_SERVER[$key];
        } elseif (isset($_ENV[$key])) {
            return $_ENV[$key];
        } else {
            return null;
        }
    }

    /**
     * 魔术方法调用 get
     *
     * @param  string  $key
     * @return mixed
     */
    public function __get($key)
    {
        return $this->get($key);
    }

    /**
     * 设置 Http Request 参数
     *
     * @param  mixed  $key
     * @param  mixed  $value
     */
    public function set($key, $value)
    {
        throw new EGP_Exception('Setting values in superglobals not allowed; please use setParam()');
    }

    /**
     * 魔术方法调用 set
     *
     * @param  string  $key
     * @param  mixed   $value
     * @return mixed
     */
    public function __set($key, $value)
    {
        return $this->set($key, $value);
    }

    /**
     * 判断是否存在指定的 Http Request Key
     *
     * @param  string  $key
     * @return boolean
     */
    public function has($key)
    {
        $value = $this->get($key);
        return empty($value) ? false : true;
    }

    /**
     * 魔术方法调用 has
     *
     * @param  string  $key
     * @return boolean
     */
    public function __isset($key)
    {
        return $this->has($key);
    }

}